﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Collections.Specialized;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using Lcsoft.UrlRewriter.Utilities;

namespace Lcsoft.UrlRewriter
{
	/// <summary>
	/// 为地址重写提供上下文信息。无法继承此类。
	/// </summary>
	public sealed class RewriteContext
	{
		private readonly RewriterEngine _engine;
		private readonly MapPath _mapPath;

		/// <summary>
		/// 初始化 <see cref="RewriteContext"/> 类的新实例。
		/// </summary>
		/// <param name="engine">地址重写引擎的实例。</param>
		/// <param name="rawUrl">原始请求地址。</param>
		/// <param name="httpMethod">请求类型。</param>
		/// <param name="mapPath">包含路径映射功能的委托。</param>
		/// <param name="serverVariables">服务器变量的集合。</param>
		/// <param name="headers">标头信息的集合。</param>
		/// <param name="cookies"><see cref="HttpCookie"/> 的集合。</param>
		internal RewriteContext(RewriterEngine engine, string rawUrl, string httpMethod, MapPath mapPath, NameValueCollection serverVariables, NameValueCollection headers, HttpCookieCollection cookies)
		{
			if (engine == null) throw new ArgumentNullException("engine");
			if (rawUrl == null) throw new ArgumentNullException("rawUrl");
			if (httpMethod == null) throw new ArgumentNullException("httpMethod");
			if (mapPath == null) throw new ArgumentNullException("mapPath");
			if (serverVariables == null) throw new ArgumentNullException("serverVariables");
			if (headers == null) throw new ArgumentNullException("headers");
			if (cookies == null) throw new ArgumentNullException("cookies");

			this.Cookies = new HttpCookieCollection();
			this.StatusCode = HttpStatusCode.OK;
			this.Headers = new NameValueCollection();
			this.Properties = new NameValueCollection();

			this._engine = engine;
			this._mapPath = mapPath;
			this.Location = rawUrl;
			this.Method = httpMethod;

			foreach (string key in serverVariables) this.Properties.Add(key, serverVariables[key]);
			foreach (string key in headers) this.Properties.Add(key, headers[key]);
			foreach (string key in cookies)
			{
				var cookie = cookies[key];

				if (cookie == null) continue;

				this.Properties.Add(key, cookie.Value);
			}
		}

		/// <summary>
		/// 获取或设置请求地址。该地址原始形式为 <see cref="HttpRequest.RawUrl"/>，之后可能会被重写。
		/// </summary>
		public string Location { get; set; }

		/// <summary>
		/// 获取请求类型(GET, PUT, POST, HEAD, DELETE)。
		/// </summary>
		public string Method { get; private set; }

		/// <summary>
		/// 获取属性信息集合。
		/// </summary>
		public NameValueCollection Properties { get; private set; }

		/// <summary>
		/// 获取标头信息集合。
		/// </summary>
		public NameValueCollection Headers { get; private set; }

		/// <summary>
		/// 获取或设置 HTTP 状态码。
		/// </summary>
		public HttpStatusCode StatusCode { get; set; }

		/// <summary>
		/// 获取 <see cref="HttpCookie"/> 的集合。
		/// </summary>
		public HttpCookieCollection Cookies { get; private set; }

		/// <summary>
		/// 获取或设置最后一个匹配项。
		/// </summary>
		public Match LastMatch { get; set; }

		/// <summary>
		/// 表示获取指定 url 映射路径的功能的委托。
		/// </summary>
		/// <param name="url">要获取其映射路径的 url。</param>
		/// <returns>返回 <paramref name="url"/> 的映射路径。</returns>
		public string MapPath(string url) { return this._mapPath(url); }

		/// <summary>
		/// 扩展或填充所选输入。
		/// </summary>
		/// <param name="input">包含要处理的输入的 <see cref="System.String"/>。</param>
		/// <returns>返回包含处理之后的输入的 <see cref="System.String"/>。</returns>
		public string Expand(string input) { return this._engine.Expand(this, input); }

		/// <summary>
		/// 解析地址信息。
		/// </summary>
		/// <param name="location">包含要解析的地址的 <see cref="System.String"/>。</param>
		/// <returns>返回包含解析之后的地址的 <see cref="System.String"/>。</returns>
		public string ResolveLocation(string location) { return this._engine.ResolveLocation(location); }
	}
}
